﻿using System;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
using com.IronOne.BoardPACWinAppUtil.Util;
using Buffer = System.Buffer;

namespace com.IronOne.BoardPACWinAppUtil.Security
{

    public class CryptoService
    {
        //private String _strAlgName = SymmetricAlgorithmNames.AesCbc;
        //public static string HashPassword(string password)
        //{
        //    return BCrypt.Net.BCrypt.HashPassword(password, BCrypt.Net.BCrypt.GenerateSalt(11));
        //}

        //public static bool VerifyPassword(string password, string hash)
        //{
        //    return BCrypt.Net.BCrypt.Verify(password, hash);
        //}

        public static String HashPasswordB(string randomString, String password)
        {
            //Random random = new Random();
            //uint saltSize = (uint)random.Next(10, 15);
            //// following not available in Windows RT
            ////RNGCryptoServiceProvider randSalt = new RNGCryptoServiceProvider();
            ////rng.GetNonZeroBytes(saltBytes);

            //IBuffer randomBuffer = CryptographicBuffer.GenerateRandom(saltSize);
            //string randomString = CryptographicBuffer.EncodeToBase64String(randomBuffer);
            randomString = randomString.Trim().Replace('a', '7').Replace('S', 'a').Replace('7', 'S');
            char[] charA = randomString.ToCharArray();
            Array.Reverse(charA);
            password = new String(charA) + password;

            var passwordBufferInUtf8 = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
            var hashAlgorithm = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha512);
            var buffHash = hashAlgorithm.HashData(passwordBufferInUtf8);

            // Verify that the hash length equals the length specified for the algorithm.
            if (buffHash.Length != hashAlgorithm.HashLength)
            {
                throw new Exception("Error when creating the Hash");
            }
            return CryptographicBuffer.EncodeToHexString(buffHash);
        }

        public static bool VerifyPasswordB(string password, string randomString, string hash)
        {
            return hash.Equals(HashPasswordB(randomString, password));
        }

        public static IBuffer EncryptFile(byte[] filedata, string openFile, byte[] initializatioVector)
        {
            var objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
            var fileBuffer = CryptographicBuffer.CreateFromByteArray(filedata);
            var ivBuffer = CryptographicBuffer.CreateFromByteArray(initializatioVector);
            var privateKbuffer =
                objAlg.CreateSymmetricKey(CryptographicBuffer.ConvertStringToBinary(openFile, BinaryStringEncoding.Utf8));
            return CryptographicEngine.Encrypt(privateKbuffer, fileBuffer, ivBuffer);
        }

        public static IBuffer DecryptFile(IBuffer encryptedBuffer, string openFile, int SEVersion)
        {
            try
            {
                IBuffer encryptedPdfBuffer;
                byte[] initializatioVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

                if (SEVersion != ApplicationConstants.VersionThreeSharedS)
                {
                    byte[] encrypted;
                    CryptographicBuffer.CopyToByteArray(encryptedBuffer, out encrypted);
                    Buffer.BlockCopy(encrypted, 0, initializatioVector, 0, 16);
                    var encryptedPdf = new byte[(encrypted.Length / 16 - 1) * 16];
                    Buffer.BlockCopy(encrypted, 16, encryptedPdf, 0, encrypted.Length - 16);
                    encryptedPdfBuffer = CryptographicBuffer.CreateFromByteArray(encryptedPdf);
                }
                else
                {
                    encryptedPdfBuffer = encryptedBuffer;
                }
                var objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);

                var ivBuffer = CryptographicBuffer.CreateFromByteArray(initializatioVector);
                var privateKbuffer =
                    objAlg.CreateSymmetricKey(CryptographicBuffer.ConvertStringToBinary(openFile,
                        BinaryStringEncoding.Utf8));

                var ibuf = CryptographicEngine.Decrypt(privateKbuffer, encryptedPdfBuffer, ivBuffer);
                return ibuf;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public IBuffer SampleCipherEncryption(String strMsg, String strAlgName, UInt32 keyLength,
            out BinaryStringEncoding encoding, out IBuffer iv, out CryptographicKey key)
        {
            // Initialize the initialization vector.
            iv = null;

            // Initialize the binary encoding value.
            encoding = BinaryStringEncoding.Utf8;

            // Create a buffer that contains the encoded message to be encrypted. 
            var buffMsg = CryptographicBuffer.ConvertStringToBinary(strMsg, encoding);

            // Open a symmetric algorithm provider for the specified algorithm. 
            var objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);

            // Demonstrate how to retrieve the name of the algorithm used.

            // Determine whether the message length is a multiple of the block length.
            // This is not necessary for PKCS #7 algorithms which automatically pad the
            // message to an appropriate length.
            if (!strAlgName.Contains("PKCS7"))
            {
                if ((buffMsg.Length % objAlg.BlockLength) != 0)
                {
                    throw new Exception("Message buffer length must be multiple of block length.");
                }
            }

            // Create a symmetric key.
            var keyMaterial = CryptographicBuffer.GenerateRandom(keyLength);
            key = objAlg.CreateSymmetricKey(keyMaterial);

            // CBC algorithms require an initialization vector. Here, a random
            // number is used for the vector.
            if (strAlgName.Contains("CBC"))
            {
                iv = CryptographicBuffer.GenerateRandom(objAlg.BlockLength);
            }

            // Encrypt the data and return.
            var buffEncrypt = CryptographicEngine.Encrypt(key, buffMsg, iv);
            return buffEncrypt;
        }

        public void SampleCipherDecryption(String strAlgName, IBuffer buffEncrypt, IBuffer iv,
            BinaryStringEncoding encoding, CryptographicKey key)
        {
            // Declare a buffer to contain the decrypted data.

            // Open an symmetric algorithm provider for the specified algorithm. 
            SymmetricKeyAlgorithmProvider.OpenAlgorithm(strAlgName);

            // The input key must be securely shared between the sender of the encrypted message
            // and the recipient. The initialization vector must also be shared but does not
            // need to be shared in a secure manner. If the sender encodes a message string 
            // to a buffer, the binary encoding method must also be shared with the recipient.
            var buffDecrypted = CryptographicEngine.Decrypt(key, buffEncrypt, iv);

            // Convert the decrypted buffer to a string (for display). If the sender created the
            // original message buffer from a string, the sender must tell the recipient what 
            // BinaryStringEncoding value was used. Here, BinaryStringEncoding.Utf8 is used to
            // convert the message to a buffer before encryption and to convert the decrypted
            // buffer back to the original plaintext.
            CryptographicBuffer.ConvertBinaryToString(encoding, buffDecrypted);
        }
    }










}